﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EvoAlgLib
{
    public abstract class Selector
    {
        protected List<Individual> population;
        protected Dictionary<double, Individual> fitTable;
        private bool expRank = false;
        private double s;

        public Selector(double param)
        {
            if (param < 1)
                expRank = true;
            else
                s = param;
        }

        public abstract List<Individual> select();

        public void resetTable(List<Individual> pop)
        {
            fitTable = new Dictionary<double, Individual>();
            this.population = pop;
            this.population.Sort();
            if (expRank)
                expRankBasedReset();
            else
                liniarRankBasedReset();
        }

        private void liniarRankBasedReset()
        {
            double soFar = 0;
            int mu = population.Count;
            for (int i = 0; i < population.Count; i++)
            {
                soFar += ((2 - s) / (double)mu + (2 * (i + 1) * (s - 1)) / (double)(mu * (mu - 1)));
                if (!fitTable.ContainsKey(soFar))
                    fitTable.Add(soFar, population[i]);
            }
        }

        /* not safe to use yet!! */
        private void expRankBasedReset()
        {
            double soFar = 0;
            int mu = population.Count;
            double c = 0;
            for (int i = 0; i < population.Count; i++)
            {
                c += (1-Math.Exp(-(i + 1)));
            }
            for (int i = 0; i < population.Count; i++)
            {
                soFar += ((1 - Math.Exp(-(i + 1))) / c);
                if (!fitTable.ContainsKey(soFar))
                    fitTable.Add(soFar, population[i]);
            }
        }

        public Individual getWeakest()
        {
            Individual min = null;
            foreach (Individual ind in population)
                if (ind.getFitness() < min.getFitness())
                    min = ind;
            return min;
        }
    }
}
